<template>
  <div class="validate-input-container pb-3">
    <input class="form-control" :class="{ 'is-invalid': inputRef.error }" v-model="inputRef.val" @blur="validateInput" v-bind="$attrs" v-if="tag === 'input'" />
    <textarea class="form-control" :class="{ 'is-invalid': inputRef.error }" v-model="inputRef.val" @blur="validateInput" v-bind="$attrs" v-else />
    <span class="invalid-feedback" v-if="inputRef.error">{{ inputRef.message }}</span>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, onMounted, PropType, reactive } from "vue";
import { RuleProps, TagType } from "../types";
import { emitter } from "./ValidateForm.vue";

const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;

export default defineComponent({
  name: "ValidateInput",
  props: {
    rules: Array as PropType<RuleProps[]>,
    tag: {
      type: String as PropType<TagType>,
      default: "input",
    },
    modelValue: String, // https://v3.cn.vuejs.org/guide/migration/v-model.html
  },
  // 禁用 Attribute 继承 https://v3.cn.vuejs.org/guide/component-attrs.html
  inheritAttrs: false,
  setup(props, { emit }) {
    const modelValue = computed({
      get: () => props.modelValue || "",
      set: (val) => emit("update:modelValue", val),
    });

    const inputRef = reactive({
      val: modelValue,
      error: false,
      message: "",
    });

    const validateInput = () => {
      if (props.rules) {
        const isBelowThreshold = (currentValue: RuleProps) => {
          let passed = true;
          inputRef.message = currentValue.message;
          switch (currentValue.type) {
            case "required":
              passed = inputRef.val.trim() !== "";
              break;
            case "email":
              passed = emailReg.test(inputRef.val);
              break;
            default:
              break;
          }
          return passed;
        };
        const allPassed = props.rules.every(isBelowThreshold);
        inputRef.error = !allPassed;
        return allPassed;
      }
      return true;
    };

    // 子组件派发事件给父组件
    onMounted(() => {
      emitter.emit("formItemCreated", validateInput);
    });

    return {
      inputRef,
      validateInput,
    };
  },
});
</script>
